package calculate

import (
	"codejy/globalfunc"
	"codejy/store"
	"codejy/structdef"
	"codejy/utils"
	"errors"
	"strings"
)

func init() {
	globalfunc.RegisterFuncAll("CalculateHandler", CalculateHandler)
	globalfunc.RegisterFuncAll("CalculateExpression", CalculateExpression)
	globalfunc.RegisterFuncAll("IsExpression", IsExpression)
}

type Calculate interface {
	//获取计算器名称,+,-,*,/,%,^......
	GetName() string
	//判断是否满足执行计算器的条件
	IsBool(symbol string) bool
	//表达式
	AddExpression(a, symbol, b string)
	// 计算
	Calculate()
	//获取结果
	GetResult() string
	//获取计算器的优先级,0优先级最高,越大优先级越低
	GetPriority() int
}
type CalculateData struct {
	//值1
	A string
	//符号
	Symbol string
	//值2
	B string
}

var Calculates = make(map[string]Calculate)
var SymbolSlip []string

// 所有技算符号,按照优先级分组
var SymbolGroup = make(map[int][]string)
var MaxPriority int

// 注册计算器
func RegisterCalculate(c Calculate) {
	//判断是否已经注册过
	if _, ok := Calculates[c.GetName()]; ok {
		panic(errors.New("计算器已经注册过了: " + c.GetName()))
	}
	//添加到策略列表
	Calculates[c.GetName()] = c
	//添加到符号列表
	SymbolGroup[c.GetPriority()] = append(SymbolGroup[c.GetPriority()], c.GetName())
	//获取最大优先级
	if c.GetPriority() > MaxPriority {
		MaxPriority = c.GetPriority()
	}
	//添加到符号切片,按照字符串长度排序从大到小
	SymbolSlip = append(SymbolSlip, c.GetName())
	utils.SortSlice[string](&SymbolSlip, 1, func(a, b string) int {
		return len(a) - len(b)
	})
}

// 计算表达式,然后赋值给变量
func CalculateHandler(threadStore *structdef.ThreadStore, currentLineCode structdef.LineCodeDefinition) {
	//获取表达式
	expression := currentLineCode.LineContent
	//拿到=左边的变量
	variableIndex := strings.Index(expression, "=")
	variable := expression[:variableIndex]
	//拿到=右边的表达式
	expression1 := expression[variableIndex+1:]
	//计算表达式,返回结果
	calculateExpression1 := CalculateExpression(threadStore, expression1)

	var variableType = globalfunc.ExecuteFunc("CodeAnalysis", threadStore, calculateExpression1).(int)
	//将计算结果赋值给变量
	store.ModifyVariable(threadStore, structdef.NewVarDefinitionValue(variable, calculateExpression1, variableType))

}

// 按照优先级计算表达式,并返回结果
func CalculateExpression(threadStore *structdef.ThreadStore, expression string) string {
	var funcMaps map[string]string
	//判断表单中是否存在函数调用
	if globalfunc.ExecuteFunc("IsCalculateFunctionCall", expression).(bool) {
		funcMaps, expression = utils.FuncExpressionReplace(expression)
	}
	//判断是否有()
	if strings.Index(expression, "(") == -1 || strings.Index(expression, ")") == -1 {
		//找不到括号,那么就直接计算
		return CalculateExpressionSplit(threadStore, expression, funcMaps)
	}
	//判断()是否成对出现
	if strings.Count(expression, "(") != strings.Count(expression, ")") {
		panic("表达式中的()不成对出现")
	}
	//找到最后一个(,然后找到第一个),然后计算,然后替换
	lastIndex := strings.LastIndex(expression, "(")
	firstIndex := strings.Index(expression[lastIndex:], ")")
	if firstIndex == -1 {
		panic(errors.New("括号不匹配"))
	}

	//取出表达式
	newExpression := expression[lastIndex+1 : lastIndex+firstIndex]
	if newExpression == "" { //如果括号内表达式是空的那么直接计算
		return CalculateExpressionSplit(threadStore, expression, funcMaps)
	}
	//计算括号内的表达式
	var result = CalculateExpressionSplit(threadStore, newExpression, funcMaps)
	//实际值替换括号内的表达式
	expression = expression[:lastIndex] + result + expression[lastIndex+firstIndex+1:]
	//继续寻找括号
	return CalculateExpression(threadStore, expression)
}
func CalculateSplit(expression string) []string {
	//如果是地址调用,那么就直接返回,不需要才分
	if strings.HasPrefix(expression, "@#@") {
		return []string{expression}
	}
	//判断是存在字符串,将字符串替换成占位符
	var strMap map[string]string
	if strings.Contains(expression, "\"") {
		mapS, str := utils.StrReplace(expression)
		strMap = mapS
		expression = str
	}

	//将 Symbol中的符号倒序替换成占位符
	var symbolSlipMap = make(map[string]string)
	symbollen := len(SymbolSlip)
	if !globalfunc.ExecuteFunc("IsIncrementDecrement", expression).(bool) {
		for i := 0; i < symbollen; i++ {
			//单独处理!,因为!是单目运算符,所以需要特殊处理
			if SymbolSlip[i] == "!" {
				continue
			} else {
				//判断是否存在
				if strings.Contains(expression, SymbolSlip[i]) {
					runes := "@symbol@" + utils.RandStringRunes()
					expression = strings.ReplaceAll(expression, SymbolSlip[i], " "+runes+" ") //留出空格,方便后面分割
					symbolSlipMap[runes] = SymbolSlip[i]
				}
			}

		}
	}

	//将表达式按照空格分割
	split := strings.Split(expression, " ")
	//将分割占位符替换回来
	for i := range split {
		s, p := symbolSlipMap[split[i]]
		if p {
			split[i] = s
		}
	}
	//将字符串替换回来
	for i := range split {
		for k, v := range strMap {
			split[i] = strings.ReplaceAll(split[i], k, v)
		}
	}

	return split
}

// 计算表达式 1+2*3=7
func CalculateExpressionSplit(threadStore *structdef.ThreadStore, expression string, funcMaps map[string]string) string {
	split := CalculateSplit(expression) //表达式拆分
	//如果存在函数调用,那么就替换回去
	if len(funcMaps) != 0 {
		for i := range split {
			for k, v := range funcMaps {
				split[i] = strings.ReplaceAll(split[i], k, v)
			}
		}
	}
	//处理0,2,4值中是否存在!,如果存在,那么就计算,然后替换
	for i := 0; i < len(split); i += 2 {
		if split[i][0] == '!' {
			//计算表达式
			calculateData := CalculateData{
				A:      "",
				Symbol: "!",
				B:      split[i][1:],
			}
			//计算表达式
			result := calculateMode(threadStore, calculateData)
			split[i] = result
		}
	}
	//按照优先级计算,如果没有优先相同的,那么就按照顺序计算
	for i := 1; i <= MaxPriority; i++ {
		if len(split) == 1 {
			return globalfunc.ExecuteFunc("AssignmentStrategyMode", threadStore, split[0]).(string)
		}
		var multi []int
		for f, s := range SymbolGroup[i] { //从表达式中找存在的符号,然后记录下标,如果存在多个符号,那么就表示有优先级相同的符号,那么就需要按照顺序计算
			if strings.Contains(expression, s) { //不包含符号,那么就跳过
				multi = append(multi, f)
			}
		}
		if len(multi) > 0 {
			if len(multi) == 1 { //只有一个符号,那么就直接计算
				for j := 1; j < len(split); j += 2 {
					if split[j] == SymbolGroup[i][multi[0]] { //找到符号
						//计算表达式
						calculateData := CalculateData{
							A:      split[j-1],
							Symbol: split[j],
							B:      split[j+1],
						}
						//计算表达式
						result := calculateMode(threadStore, calculateData)
						//替换表达式
						split[j-1] = result
						//删除表达式
						split = append(split[:j], split[j+2:]...)
						//重新计算
						j = -1
					}
				}

			} else { //多个符号,那么就按照顺序计算
				//按照顺序计算
				for j := 1; j < len(split); j += 2 {
					for _, k := range multi {
						if split[j] == SymbolGroup[i][k] { //找到符号
							//计算表达式
							calculateData := CalculateData{
								A:      split[j-1],
								Symbol: split[j],
								B:      split[j+1],
							}
							//计算表达式
							result := calculateMode(threadStore, calculateData)
							//替换表达式
							split[j-1] = result
							//删除表达式
							split = append(split[:j], split[j+2:]...)
							//重新计算
							j = -1
							break

						}
					}
				}

			}

		}

	}
	if len(split) == 0 {
		return ""
	}
	return split[0]
}

// 策略模式
func calculateMode(threadStore *structdef.ThreadStore, calculateData CalculateData) string {
	//如果是实例地址那么就报错
	var analysis, analysis1 = -1, -1
	if calculateData.A != "" {
		analysis = globalfunc.ExecuteFunc("CodeAnalysis", threadStore, calculateData.A).(int)
	}
	if calculateData.B != "" {
		analysis1 = globalfunc.ExecuteFunc("CodeAnalysis", threadStore, calculateData.B).(int)
	}
	instanceAddress := globalfunc.ExecuteFunc("GetInstanceAddress").(int)
	if analysis == instanceAddress || analysis1 == instanceAddress {
		panic(errors.New("实例变量不能参与运算"))
	}
	//参数转换
	if calculateData.A != "" {
		calculateData.A = globalfunc.ExecuteFunc("AssignmentStrategyMode", threadStore, calculateData.A).(string)
	}
	if calculateData.B != "" {
		calculateData.B = globalfunc.ExecuteFunc("AssignmentStrategyMode", threadStore, calculateData.B).(string)
	}

	for _, c := range Calculates {
		c.AddExpression(calculateData.A, calculateData.Symbol, calculateData.B)
		if c.IsBool(calculateData.Symbol) {
			c.Calculate()
			return c.GetResult()
		}
	}
	panic("没有找到对应的计算器->[ " + calculateData.Symbol + " ]请检查是否支持该计算器")
}

// 判断字符串中是否包含符号,如果包含,那么就是表达式,需要计算
func IsExpression(str1 string) bool {
	_, str := utils.StrReplace(str1) //取消字符串
	//判断是否是表达式,检测是否存在Symbol
	for i := range SymbolSlip {
		if strings.Contains(str, SymbolSlip[i]) {
			return true
		}
	}
	return false
}
